package com.g.ocache.impl.index;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import com.g.ocache.enums.VisitingOrder;
import com.g.ocache.index.Node;


/**
 * 
 * @author zhangyf
 * @param <K>
 * @param <V>
 */
public abstract class AbstractNode<K, V> implements Node<K, V> {
	//
	private final Object id;
	private final Node<K, V> parent;
	private volatile boolean initialized;
	
	/**
	 * 
	 */
	public AbstractNode(Object id, Node<K, V> parent) {
		//
		this.id = id;
		this.parent = parent;
		
		//
		if(this.parent != null) {
			this.parent.addChild(id, this);
		}
	}
	
	/**
	 * 
	 */
	public final Object getId() {
		return id;
	}
	
	public final List<Object> getIdPath() {
		//
		if(getId() == null) {
			return new ArrayList<Object>(0);
		}
		
		//
		LinkedList<Object> r = new LinkedList<Object>();
		r.add(getId());
		Node<K, V> node = getParent();
		while(node != null) {
			if(node.getId() != null) {
				r.addFirst(node.getId());
			}
			node = node.getParent();
		}
		return r;
	}
	
	public final Node<K, V> getParent() {
		return parent;
	}
	
	public final int getDepth() {
		int depth = 0;
		Node<K, V> node = getParent();
		while(node != null) {
			depth++;
			node = node.getParent();
		}
		return depth;
	}
	
	public final Node<K, V> getRoot() {
		Node<K, V> node = this;
		while(node.getParent() != null) {
			node = node.getParent();
		}
		return node;
	}
	
	/**
	 * 
	 */
	public final boolean isInitialized() {
		//
		if(initialized) {
			return true;
		} 
		
		//
		if(getParent() != null) {
			return getParent().isInitialized();
		} else {
			return false;
		}
	}
	
	public final void setInitialized(boolean initialized) {
		this.initialized = initialized;
	}
	
	/**
	 * 
	 */
	public final void visit(Node.Visitor<K, V> visitor, VisitingOrder order) {
		//
		if(order == VisitingOrder.preOrder) {
			visitor.visit(this);
		}
		
		//
		for (Node<K, V> child : getChildren()) {
			child.visit(visitor, order);
		}
		
		//
		if(order == VisitingOrder.postOrder) {
			visitor.visit(this);
		}
	}
}
